
import copy
import thread

from coffeetalk.protocol import ioml
from coffeetalk.utilities import iologger

class Extension(object):
    
    def __init__(self,ioconnection,log=iologger.IONullLogger()):
        
        ioconnection.message_handler = self.process_message
        self.clients = [ioconnection]
        self.log = log
                
        self.requests = {}
        self.requestslock = thread.allocate_lock()
        
        self.subscribers = []
        self.subscriberslock = thread.allocate_lock()
        
        self.monitors = {}
        self.monitorlock = thread.allocate_lock()
    
    def client_count(self):
        self.requestslock.acquire()
        returncount = len(self.clients)
        self.requestslock.release()
        return returncount
    
    def add_client(self,newclient):    
        self.requestslock.acquire()
        newclient.message_handler = self.process_message
        self.clients.append(newclient)
        self.requestslock.release()
        
    def remove_client(self,oldclient):
        self.requestslock.acquire()
        if oldclient in self.clients:
            self.clients.remove(oldclient)
        self.requestslock.release()
    
    def add_subscriber(self,subscriber):
        self.subscriberslock.acquire()
        self.subscribers.append(subscriber)
        self.subscriberslock.release()
    
    def remove_subscriber(self,subscriber):
        self.subscriberslock.acquire()
        if subscriber in self.subscribers:
            self.subscribers.remove(subscriber)
        self.subscriberslock.release()
    
    def add_monitor(self,monitortype,monitor):
        self.monitorlock.acquire()
        if not self.monitors.has_key(monitortype):
            self.monitors[monitortype] = []
        self.monitors[monitortype].append(monitor)
        self.monitorlock.release()
        
    def remove_monitor(self,monitortype,monitor):
        self.monitorlock.acquire()
        if self.monitors.has_key(monitortype) and monitor in self.monitors[monitortype]:
            self.monitors[monitortype].remove(monitor)
        self.monitorlock.release()
           
    def send_request(self,env,request,client):
        
        self.requestslock.acquire()
        
        newrequest = _ExtensionRequest(copy.deepcopy(request),client)
        requestid = str(id(client)) + ':' + str(env.requestid)       
        self.requests[requestid] = newrequest
        
        request.headelement.set_attribute('requestid',requestid)
        request.headelement.add(env.element)
        
        requeststring = str(request)
        for client in self.clients:
            client.connection.send_message(requeststring)        
        
        self.requestslock.release()
        
    def process_message(self,message):
        
        response = ioml.IOML(iomlstring=message)
        requestid = response.headelement.name
        responsetype = response.headelement.attribs['type']
        
        self.requestslock.acquire()
        if self.requests.has_key(requestid):
            extensionrequest = self.requests[requestid]
            request = extensionrequest.request
            client = extensionrequest.client
            requesttype = request.headelement.attribs['type']
            response.headelement.set_name(request.headelement.attribs['requestid'])
            
            if requesttype == 'Subscribe' and responsetype == 'responses.OK':
                self.add_subscriber(client.connection.send_message)
                client.add_subscription(request.headelement.attribs['path'])
            elif requesttype == 'Unsubscribe' and responsetype == 'responses.OK':
                self.remove_subscriber(client.connection.send_message)
                client.remove_subscription(request.headelement.attribs['path'])
            elif requesttype == 'AddMonitor':
                self.add_monitor(request.headelement.attribs['monitortype'], client.connection.send_message)
                client.add_monitor(request.headelement.attribs['path'],request.headelement.attribs['monitortype'])
            elif requesttype == 'DeleteMonitor':
                self.remove_monitor(request.headelement.attribs['monitortype'], client.connection.send_message)
                client.remove_monitor(request.headelement.attribs['path'],request.headelement.attribs['monitortype'])
            
            try:
                client.connection.send_message(str(response))
            except: pass
            
            if not responsetype == 'responses.PartialContent':
                del self.requests[requestid]
            
            self.requestslock.release()      
        
        else:
            self.requestslock.release()
            
            if response.headelement.name == 'Update':
                self.subscriberslock.acquire()
                for subscriber in self.subscribers:
                    subscriber(message)
                self.subscriberslock.release()
            elif response.headelement.name == 'Monitor':
                monitortype = response.headelement.attribs['type']
                self.monitorlock.acquire()
                if self.monitors.has_key(monitortype):
                    for monitor in self.monitors[monitortype]:
                        monitor(message)
                self.monitorlock.release()
            else:
                print 'Unknown response!!!'
        
class _ExtensionRequest(object):
    
    def __init__(self,request,client):
        self.request = request
        self.client = client
        